package org.hawksee.core.tools;

/*
 * This class performs transformations on images.
 */
public class Transformer
{
  public enum Transformation
  {
    TRANSLATION,
    SCALED_ROTATION,
    RIGID_BODY,
    AFFINE,
    BILINEAR,
  }

  /*
  private static double[][] calculateMatrix(double[][] fromCoord, double[][] toCoord, 
      Transformation transformation)
  {
    double[][] matrix = null;
    double[][] a = null;
    double[] v = null;
    switch (transformation) {
      case TRANSLATION : {
        matrix = new double[2][1];
        matrix[0][0] = toCoord[0][0] - fromCoord[0][0];
        matrix[1][0] = toCoord[0][1] - fromCoord[0][1];
        break;
      }
      case RIGID_BODY : {
        final double angle = Math.atan2(fromCoord[2][0] - fromCoord[1][0],
            fromCoord[2][1] - fromCoord[1][1])
            - Math.atan2(toCoord[2][0] - toCoord[1][0], toCoord[2][1]
                - toCoord[1][1]);
        final double c = Math.cos(angle);
        final double s = Math.sin(angle);
        matrix = new double[2][3];
        matrix[0][0] = toCoord[0][0] - c * fromCoord[0][0] + s
            * fromCoord[0][1];
        matrix[0][1] = c;
        matrix[0][2] = -s;
        matrix[1][0] = toCoord[0][1] - s * fromCoord[0][0] - c
            * fromCoord[0][1];
        matrix[1][1] = s;
        matrix[1][2] = c;
        break;
      }
      case SCALED_ROTATION : {
        matrix = new double[2][3];
        a = new double[3][3];
        v = new double[3];
        a[0][0] = 1.0;
        a[0][1] = fromCoord[0][0];
        a[0][2] = fromCoord[0][1];
        a[1][0] = 1.0;
        a[1][1] = fromCoord[1][0];
        a[1][2] = fromCoord[1][1];
        a[2][0] = 1.0;
        a[2][1] = fromCoord[0][1] - fromCoord[1][1] + fromCoord[1][0];
        a[2][2] = fromCoord[1][0] + fromCoord[1][1] - fromCoord[0][0];
        Calculator.invertGauss(a);
        v[0] = toCoord[0][0];
        v[1] = toCoord[1][0];
        v[2] = toCoord[0][1] - toCoord[1][1] + toCoord[1][0];
        for (int i = 0; (i < 3); i++) {
          matrix[0][i] = 0.0;
          for (int j = 0; (j < 3); j++) {
            matrix[0][i] += a[i][j] * v[j];
          }
        }
        v[0] = toCoord[0][1];
        v[1] = toCoord[1][1];
        v[2] = toCoord[1][0] + toCoord[1][1] - toCoord[0][0];
        for (int i = 0; (i < 3); i++) {
          matrix[1][i] = 0.0;
          for (int j = 0; (j < 3); j++) {
            matrix[1][i] += a[i][j] * v[j];
          }
        }
        break;
      }
      case AFFINE : {
        matrix = new double[2][3];
        a = new double[3][3];
        v = new double[3];
        a[0][0] = 1.0;
        a[0][1] = fromCoord[0][0];
        a[0][2] = fromCoord[0][1];
        a[1][0] = 1.0;
        a[1][1] = fromCoord[1][0];
        a[1][2] = fromCoord[1][1];
        a[2][0] = 1.0;
        a[2][1] = fromCoord[2][0];
        a[2][2] = fromCoord[2][1];
        Calculator.invertGauss(a);
        v[0] = toCoord[0][0];
        v[1] = toCoord[1][0];
        v[2] = toCoord[2][0];
        for (int i = 0; (i < 3); i++) {
          matrix[0][i] = 0.0;
          for (int j = 0; (j < 3); j++) {
            matrix[0][i] += a[i][j] * v[j];
          }
        }
        v[0] = toCoord[0][1];
        v[1] = toCoord[1][1];
        v[2] = toCoord[2][1];
        for (int i = 0; (i < 3); i++) {
          matrix[1][i] = 0.0;
          for (int j = 0; (j < 3); j++) {
            matrix[1][i] += a[i][j] * v[j];
          }
        }
        break;
      }
      case BILINEAR : {
        matrix = new double[2][4];
        a = new double[4][4];
        v = new double[4];
        a[0][0] = 1.0;
        a[0][1] = fromCoord[0][0];
        a[0][2] = fromCoord[0][1];
        a[0][3] = fromCoord[0][0] * fromCoord[0][1];
        a[1][0] = 1.0;
        a[1][1] = fromCoord[1][0];
        a[1][2] = fromCoord[1][1];
        a[1][3] = fromCoord[1][0] * fromCoord[1][1];
        a[2][0] = 1.0;
        a[2][1] = fromCoord[2][0];
        a[2][2] = fromCoord[2][1];
        a[2][3] = fromCoord[2][0] * fromCoord[2][1];
        a[3][0] = 1.0;
        a[3][1] = fromCoord[3][0];
        a[3][2] = fromCoord[3][1];
        a[3][3] = fromCoord[3][0] * fromCoord[3][1];
        Calculator.invertGauss(a);
        v[0] = toCoord[0][0];
        v[1] = toCoord[1][0];
        v[2] = toCoord[2][0];
        v[3] = toCoord[3][0];
        for (int i = 0; (i < 4); i++) {
          matrix[0][i] = 0.0;
          for (int j = 0; (j < 4); j++) {
            matrix[0][i] += a[i][j] * v[j];
          }
        }
        v[0] = toCoord[0][1];
        v[1] = toCoord[1][1];
        v[2] = toCoord[2][1];
        v[3] = toCoord[3][1];
        for (int i = 0; (i < 4); i++) {
          matrix[1][i] = 0.0;
          for (int j = 0; (j < 4); j++) {
            matrix[1][i] += a[i][j] * v[j];
          }
        }
        break;
      }
    }
    return (matrix);
  } 
  public static float[] performFinalTransform(Image targetImage, Image sourceImage,
      Transformation transformation, boolean accelerate)
  {
    if (accelerate) {
      inImg = sourceImg.getImage();
    } else {
      inImg = sourceImg.getCoefficient();
    }
    int inNx = sourceImage.getWidth();
    int inNy = sourceImage.getHeight();
    int outNx = targetImage.getWidth();
    int outNy = targetImage.getHeight();
    float[] outImg = new float[outNx * outNy];
    double[][] matrix = calculateMatrix(targetImage.getPoints(), sourceImage.getPoints(),
        transformation);
    switch (transformation) {
      case TRANSLATION : {
        performTranslation(matrix, accelerate);
        break;
      }
      case RIGID_BODY :
      case SCALED_ROTATION :
      case AFFINE : {
        affineTransform(matrix);
        break;
      }
      case BILINEAR : {
        bilinearTransform(matrix);
        break;
      }
    }
    return (outImg);
  }
  private static void performTranslation(float[] imagePoints, double[][] matrix, boolean accelerate)
  {
    double dx = matrix[0][0];
    double dy = matrix[1][0];
    final double dx0 = dx;
    int xMsk;
    int yMsk;
    double x = dx - Math.floor(dx);
    double y = dy - Math.floor(dy);
    if (!accelerate) {
      xWeights();
      yWeights();
    }
    int k = 0;
    for (int v = 0; (v < outNy); v++) {
      y = dy++;
      yMsk = (0.0 <= y) ? ((int) (y + 0.5)) : ((int) (y - 0.5));
      if ((0 <= yMsk) && (yMsk < inNy)) {
        yMsk *= inNx;
        if (!accelerate) {
          yIndexes();
        }
        dx = dx0;
        for (int u = 0; (u < outNx); u++) {
          x = dx++;
          xMsk = (0.0 <= x) ? ((int) (x + 0.5)) : ((int) (x - 0.5));
          if ((0 <= xMsk) && (xMsk < inNx)) {
            xMsk += yMsk;
            if (accelerate) {
              imagePoints[k++] = inImg[xMsk];
            } else {
              xIndexes();
              imagePoints[k++] = (float)interpolate();
            }
          } else {
            imagePoints[k++] = 0.0F;
          }
        }
      } else {
        for (int u = 0; (u < outNx); u++) {
          imagePoints[k++] = 0.0F;
        }
      }
    }
  }
  */
}
